using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace Krile.Forms.MainForm.Controls.XTab
{
    public class XTabItem : XTabItemBase,IDisposable
    {
        protected XTab parent;

        protected void Refresh()
        {
            parent.Refresh();
        }

        public XTabItem(XTab par, string n)
        {
            parent = par;
            Name = n;
            iconImage = null;
            Closed = false;
        }

        public XTabItem(XTab par, string n, Image icoImage)
            : this(par, n)
        {
            iconImage = icoImage;
            Closed = false;
        }

        public void ResetParent(XTab par)
        {
            parent = par;
        }

        public override string Name { get; set; }

        private Image iconImage;
        /// <summary>
        /// iconimage
        /// </summary>
        public Image IconImage
        {
            get { return iconImage; }
            set { iconImage = value; }
        }

        private bool selected;
        /// <summary>
        /// Selected this tab
        /// </summary>
        public bool Selected
        {
            get { return selected; }
            set
            {
                selected = value;
                if (value)
                    OnSelected();
                Refresh();
            }
        }

        private Rectangle myRegionRect;

        /// <summary>
        /// client rectangle
        /// </summary>
        public override Rectangle ClientRectangle
        {
            get { return myRegionRect; }
        }

        /// <summary>
        /// location
        /// </summary>
        public Point Location
        {
            get { return myRegionRect.Location; }
            set { myRegionRect.Location = value; }
        }

        /// <summary>
        /// Location Top
        /// </summary>
        public int Top
        {
            get { return myRegionRect.Y; }
            set { myRegionRect.Y = value; }
        }

        /// <summary>
        /// Location Left
        /// </summary>
        public int Left
        {
            get { return myRegionRect.X; }
            set { myRegionRect.X = value; }
        }

        protected bool drawCloseButton = false;
        protected virtual bool IsLocked { get { return false; } }
        bool hovering = false;
        bool hoverCloseButton = false;
        bool activeCloseButton = false;
        public bool Closed { get; private set; }
        const int closeButtonWidth = 18;
        const int iconMargin = 1;
        const int outerMargin = 2;

        public void Draw(Graphics g)
        {
            g.SmoothingMode = SmoothingMode.HighQuality;
            g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
            Rectangle innerRect = ClientRectangle;
            innerRect.Width--;
            innerRect.Height--;
            if (selected)
            {
                innerRect.Height++;
                using (Brush b = new SolidBrush(Color.White))
                {
                    g.FillRectangle(b, innerRect);
                }
            }
            else
            {
                //overflow gradation
                RectangleF cclp = g.ClipBounds;
                cclp.Height--;
                g.SetClip(cclp);
                using (var b = new LinearGradientBrush(innerRect, Color.White, Color.Gainsboro, 90f))
                    g.FillRectangle(b, innerRect);
            }
            if (hovering)
            {
                //overflow gradation
                Rectangle hovRect = innerRect;
                hovRect.Height /= 2;
                using (var b = new LinearGradientBrush(hovRect, Color.SkyBlue, Color.Transparent, 90f))
                    g.FillRectangle(b, hovRect);
            }
            if (selected)
                g.DrawRectangle(Pens.DimGray, innerRect);
            else
                g.DrawRectangle(Pens.Gray, innerRect);

            innerRect = ClientRectangle;
            if (this.iconImage != null)
            {
                Rectangle destRect = ClientRectangle;
                destRect.Width = destRect.Height;
                innerRect.X += destRect.Width;
                innerRect.Width -= destRect.Width;
                destRect.X++;
                destRect.Y++;
                destRect.Width -= 2;
                destRect.Height -= 2;
                Point destPoint = destRect.Location;
                destPoint.X += destRect.Width / 2;
                destPoint.Y += destRect.Height / 2;
                try
                {
                    destPoint.X -= iconImage.Width / 2;
                    destPoint.Y -= iconImage.Height / 2;
                    g.DrawImage(iconImage, destPoint);
                }
                catch (ArgumentException)
                {
                    destPoint.X -= 8;
                    destPoint.Y -= 8;
                    g.DrawImage(Properties.Resources.exclamation, destPoint);
                }
            }
            if (drawCloseButton)
            {
                if (hoverCloseButton)
                {
                    Rectangle destRect = ClientRectangle;
                    destRect.X += destRect.Width - closeButtonWidth * 2;
                    destRect.Width = closeButtonWidth * 2;
                    using (var lgb = new LinearGradientBrush(destRect, Color.Transparent, Color.FromArgb(activeCloseButton ? 200 : 100, Color.Red), 0f))
                    {
                        destRect.X++;
                        g.FillRectangle(lgb, destRect);
                    }
                }
                using (Image drawImage = Properties.Resources.delete_s)
                {
                    Rectangle destRect = ClientRectangle;
                    destRect.X = ClientRectangle.Right - closeButtonWidth - outerMargin;
                    destRect.Y++;
                    destRect.Width = closeButtonWidth;
                    destRect.Height -= 2;

                    innerRect.Width -= destRect.Width;

                    Point destPoint = destRect.Location;
                    destPoint.X += destRect.Width / 2;
                    destPoint.Y += destRect.Height / 2;
                    destPoint.X -= drawImage.Width / 2;
                    destPoint.Y -= drawImage.Height / 2;
                    g.DrawImage(drawImage, destPoint);
                }
            }

            // TextRenderer.DrawText wouldn't recommend Graphics.ClipBounds.
            // What shall I do any action to this fact?

            // ...temporally answer is below.

            Rectangle textRenderingRect = new Rectangle(innerRect.Location, innerRect.Size);
            textRenderingRect.Width = (int)g.ClipBounds.Width - (ClientRectangle.Width - innerRect.Width);

            if (selected)
                TextRenderer.DrawText(g, this.Name, Core.Config.Appearance.Font.Value, textRenderingRect, SystemColors.ControlText,
                    TextFormatFlags.EndEllipsis | TextFormatFlags.Left | TextFormatFlags.LeftAndRightPadding | TextFormatFlags.NoPrefix | TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter);
            else
                TextRenderer.DrawText(g, this.Name, Core.Config.Appearance.Font.Value, textRenderingRect, SystemColors.ControlDarkDark,
                    TextFormatFlags.EndEllipsis | TextFormatFlags.Left | TextFormatFlags.LeftAndRightPadding | TextFormatFlags.NoPrefix | TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter);
        }

        /// <summary>
        /// refresh this size
        /// </summary>
        /// <param name="g"></param>
        public void UpdateMeasure(Graphics g)
        {
            if (parent.FixedSize)
            {
                this.myRegionRect.Size = parent.MaxTabSize;
                if (!IsLocked && (selected || Core.Config.Appearance.TabAppearance.ShowCloseButtonForAllTab))
                    drawCloseButton = true;
                else
                    drawCloseButton = false;
                return;
            }
            this.myRegionRect.Height = parent.MaxTabSize.Height;
            this.myRegionRect.Width = 0;
            if (this.iconImage != null)
                //add height for icon drawing
                this.myRegionRect.Width += this.myRegionRect.Height;

            this.myRegionRect.Width += TextRenderer.MeasureText(g, Name, Core.Config.Appearance.Font.Value, new Size(),
                 TextFormatFlags.LeftAndRightPadding | TextFormatFlags.NoPrefix | TextFormatFlags.SingleLine).Width;
            if (!IsLocked && (selected || Core.Config.Appearance.TabAppearance.ShowCloseButtonForAllTab))
            {
                drawCloseButton = true;
                this.myRegionRect.Width += closeButtonWidth;
            }
            else
            {
                drawCloseButton = false;
            }
            if (this.myRegionRect.Width > parent.MaxTabSize.Width)
                this.myRegionRect.Width = parent.MaxTabSize.Width;
            this.myRegionRect.Width += outerMargin * 2;
        }

        public void Dispose()
        {
            if (iconImage != null)
            {
                iconImage.Dispose();
                iconImage = null;
            }
        }

        public override void OnMouseClick(object obj, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (parent.SelectedItem == this && IsInnerCloseButton(e.Location) && activeCloseButton)
                    CloseThis();
                else
                    parent.SelectedItem = this;
            }
            base.OnMouseClick(obj, e);
        }

        public override void OnMouseDoubleClick(object obj, MouseEventArgs e)
        {
            OnMouseClick(obj, e);
        }

        public override void OnMouseEnter(object obj, MouseEventArgs e)
        {
            hovering = true;
            activeCloseButton = false;
            Refresh();
        }

        public override void OnMouseLeave(object obj, MouseEventArgs e)
        {
            hovering = false;
            hoverCloseButton = false;
            Refresh();
        }

        public override void OnMouseMove(object obj, MouseEventArgs e)
        {
            hoverCloseButton = IsInnerCloseButton(e.Location);
/*            if (e.Button == MouseButtons.Left)
                activeCloseButton = IsInnerCloseButton(e.Location);*/
            Refresh();
            base.OnMouseMove(obj, e);
        }

        public override void OnMouseDown(object obj, MouseEventArgs e)
        {
            activeCloseButton = IsInnerCloseButton(e.Location);
            Refresh();
            base.OnMouseDown(obj, e);
        }

        public override void OnMouseUp(object obj, MouseEventArgs e)
        {
            activeCloseButton = false;
            Refresh();
            base.OnMouseUp(obj, e);
        }

        private bool IsInnerCloseButton(Point parentLocPoint)
        {
            if (!drawCloseButton)
                return false;
            parentLocPoint.X -= ClientRectangle.Left;
            parentLocPoint.Y -= ClientRectangle.Top;
            if (parentLocPoint.X >= ClientRectangle.Width - closeButtonWidth && parentLocPoint.X <= ClientRectangle.Width)
            {
                if (parentLocPoint.Y >= 0 && parentLocPoint.Y <= ClientRectangle.Height)
                {
                    return true;
                }
            }
            return false;
        }

        protected virtual void CloseThis()
        {
            parent.CloseTab(this);
        }

        public virtual void OnClosing()
        {
            Closed = true;
        }

        public virtual void OnSelected() { }
    }
}
